package com.lx.util.secure.algorithm.encrypt;

import com.lx.annotation.Note;
import com.lx.entity.Var;
import com.lx.util.LX;
import com.lx.util.secure.algorithm.SecureAlgorithm;
import com.lx.util.secure.algorithm.SignAlgorithm;
import com.lx.util.secure.algorithm.coder.Base64;
import com.lx.util.secure.algorithm.coder.CoderType;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.ECFieldFp;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.EllipticCurve;
import java.util.HashMap;
import java.util.Map;


@Slf4j
public class Sm2 {
    public static void main(String[] args) throws InvalidCipherTextException, IOException {

        String json = "[{\"applyDate\":\"2024-05-31\",\"channelCode\":\"2\",\"createDate\":\"2024-05-31 09:54:29\",\"deptCode\":\"103\",\"deptName\":\"内科\",\"endTime\":\"10:10\",\"handleStatus\":0,\"hosName\":\"上海助医互联网医院\",\"hosOrgCode\":\"310107202\",\"isAdd\":\"0\",\"numSourceDetailId\":\"61042465\",\"numSourceFrom\":\"4\",\"numSourceId\":\"61042465\",\"oneDeptName\":\"内科\",\"orderId\":\"499964\",\"orderNumType\":\"102\",\"orderStatus\":\"3\",\"orderTime\":\"2024-05-31\",\"orderType\":\"1\",\"patientType\":\"1\",\"payMode\":\"1\",\"payState\":\"3\",\"platformType\":\"9\",\"resourceCode\":\"1073593938\",\"resourceName\":\"杨洪杰\",\"scheduleId\":\"61042465\",\"startTime\":\"10:01\",\"timeRange\":\"1\",\"updateInsertStatus\":2,\"userBd\":\"1969-03-15\",\"userCardId\":\"232102196903151919\",\"userCardType\":\"01\",\"userName\":\"张亚春\",\"userPhone\":\"18717739352\",\"userSex\":\"1\",\"visitCost\":\"1.00\"}]";
        System.out.println("加密前>>>>>>>>>>>>>>> \n" + json);

        String encryptJson = encrypt(json, "04ff848e971bb9627c66a531da8a64d0c2e05c5d96d160c096f0d806ba7ff2206caee7a5714c6eebad8c52a9e7b486acfc00cca0ea308feac03cf4205e6aecf6fe");
        System.out.println("加密后>>>>>>>>>>>>>>> \n" + encryptJson);

        System.out.println("解密后>>>>>>>>>>>>>>> ");
        System.out.println(decrypt(encryptJson, "11f096d2702490839c7f0cdea8f003ea85a1bf822977a39403e67a14bac4bc3e"));

    }

    /**
     * encrypt
     * @param plainText 需加密的明文字符串
     * @param publicKey 公钥
     */
    public static String encrypt(String plainText, String publicKey) throws IOException, InvalidCipherTextException {
        return encrypt(plainText, publicKey, SM2Engine.Mode.C1C3C2);
    }

    /**
     * decrypt
     * @param cipherText 需加密的字符串
     * @param privateKey 私钥
     */
    public static String decrypt(String cipherText, String privateKey) throws InvalidCipherTextException, UnsupportedEncodingException {
        return decrypt(cipherText, privateKey, SM2Engine.Mode.C1C3C2);
    }


    //获取椭圆曲线
    public static synchronized ECDomainParameters getECDomainParameters() {
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        return new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
    }

    /**
     * 获取公钥私钥
     * get key pair
     */
    public static Map<String, String> createKeyPair() throws NoSuchAlgorithmException {
        ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
        keyPairGenerator.init(new ECKeyGenerationParameters(getECDomainParameters(), SecureRandom.getInstance("SHA1PRNG")));
        AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
        Map<String, String> map = new HashMap<>();
        BigInteger bigInteger = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
        map.put("pveky", ByteUtils.toHexString(bigInteger.toByteArray()));
        // 把公钥放入map中,默认压缩公钥
        // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04
        ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
        map.put("pbcky", ByteUtils.toHexString(ecPoint.getEncoded(false)));
        return map;
    }

    /**
     * 加密
     * @param plainText 需加密的明文字符串
     * @param publicKey 公钥
     * @param modeType base:标准；bc：BC模式 SM2Engine.Mode.C1C2C3
     */
    public static String encrypt(String plainText, String publicKey, SM2Engine.Mode mode) throws IOException, InvalidCipherTextException {
        return encrypt(plainText.getBytes(), publicKey, mode);
    }

    /**
     * 加密
     * @param plainByte 需加密的明文字节数组
     * @param publicKey 公钥
     * @param mode 加密模式 ModeTypeEnum
     */
    public static String encrypt(byte[] plainByte, String publicKey, SM2Engine.Mode mode) throws IOException, InvalidCipherTextException {
        ECDomainParameters domainParameters = getECDomainParameters();
        //提取公钥点
        ECPoint ecPoint = domainParameters.getCurve().decodePoint(ByteUtils.fromHexString(publicKey));
        // 公钥前面的02或者03表示是压缩公钥，04表示未压缩公钥, 04的时候，可以去掉前面的04
        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(ecPoint, domainParameters);
        SM2Engine sm2Engine = new SM2Engine(mode);
        sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));
        return ByteUtils.toHexString(sm2Engine.processBlock(plainByte, 0, plainByte.length));
    }

    /**
     * 解密
     * @param cipherText 需加密的字符串
     * @param privateKey 私钥
     * @param modeType base:标准；bc：BC模式 SM2Engine.Mode.C1C2C3
     */
    public static String decrypt(String cipherText, String privateKey, SM2Engine.Mode mode) throws InvalidCipherTextException, UnsupportedEncodingException {
        return decrypt(Hex.decode(cipherText), privateKey, mode);
    }

    /**
     * 解密
     * @param cipherDataByte 密文字节数组
     * @param privateKeyHex 私钥
     * @param mode 解密模式 ModeTypeEnum
     */
    public static String decrypt(byte[] cipherDataByte, String privateKeyHex, SM2Engine.Mode mode) throws InvalidCipherTextException, UnsupportedEncodingException {
        BigInteger bigInteger = new BigInteger(privateKeyHex, 16);
        ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(bigInteger, getECDomainParameters());
        SM2Engine sm2Engine = new SM2Engine(mode);
        sm2Engine.init(false, privateKeyParameters);
        return new String(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length), "utf-8");
    }


}
